package com.sxkiler.demo.rpc.client;

import com.sxkiler.demo.rpc.model.MessageContext;
import com.sxkiler.demo.rpc.model.Request;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;

import java.util.concurrent.ConcurrentHashMap;

/**
 * 实现Callable接口，重写call方法
 */
public class RpcClientHandler extends ChannelInboundHandlerAdapter {

    private ChannelHandlerContext channelHandlerContext;


    private ConcurrentHashMap<String,MessageContext> resMap = new ConcurrentHashMap<>();

    public RpcClientHandler() {
        super();
    }


    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        System.out.println("调用ctx方法");
        ctx.fireChannelActive();
        this.channelHandlerContext = ctx;
    }

    /**
     * channelRead会比sendRequest之后执行
     * @param ctx
     * @param msg
     * @throws Exception
     */
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        System.out.println("来自服务端的消息："+msg);
        if (msg instanceof MessageContext){
            //接收到服务端返回后，放到线程共享变量里面
            MessageContext response = (MessageContext) msg;
            MessageContext res = resMap.get(response.getMessageId());
            if(response.getSuccess()){
                System.out.println("调用服务返回值："+response.toString());
                res.setMessageId(response.getMessageId());
                res.setContext(response.getContext());
                res.setSuccess(response.getSuccess());
            }else{
                res.getCountDownLatch().countDown();
                throw new RuntimeException("服务端发生异常");
            }
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        System.out.println("发生了异常");
        cause.printStackTrace();
        ctx.close();
    }

    public synchronized MessageContext sendRequest(Request request) throws Exception {//重写call方法
        System.out.println("调用call方法");
        String messageId = request.getReqId();
        MessageContext resContext = new MessageContext();
        resMap.put(messageId,resContext);
        MessageContext reqContext = new MessageContext(messageId, true, request);
        ChannelFuture future = channelHandlerContext.channel().writeAndFlush(reqContext);
        //等待服务器返回
        future.sync();
        System.out.println("服务端返回对象了,等待channelRead");
        resContext.getCountDownLatch().await();
        //拿到数据解析并转换成相应的返回类型
        return resContext;
    }

}

